Перейти к основному содержимому

5.01. Справочник по Vue.js

Разработчику Архитектору

Справочник по Vue.js

1. Основные понятия

Экземпляр приложения

Все приложения Vue начинаются с создания экземпляра приложения через createApp.

const app = Vue.createApp({
// корневой компонент
})

Метод createApp принимает объект конфигурации корневого компонента и возвращает экземпляр приложения.

Корневой компонент

Корневой компонент определяет начальное состояние и поведение приложения. Он содержит:

  • data — реактивные данные
  • methods — методы
  • computed — вычисляемые свойства
  • watch — наблюдатели
  • setup() — точка входа для Composition API
  • template или render — шаблон или функция рендеринга

Монтирование

Приложение монтируется в DOM-элемент:

app.mount('#app')

Метод mount принимает селектор или DOM-элемент и заменяет его содержимое отрендеренным представлением компонента.


2. Реактивность

ref

Создаёт реактивную ссылку на примитивное значение.

import { ref } from 'vue'
const count = ref(0)
console.log(count.value) // 0

Значение доступно через .value.

reactive

Создаёт реактивный объект (глубокая реактивность).

import { reactive } from 'vue'
const state = reactive({ count: 0 })

Изменения любого вложенного свойства отслеживаются автоматически.

computed

Создаёт вычисляемое свойство, кэшируемое до изменения зависимостей.

import { computed } from 'vue'
const doubled = computed(() => count.value * 2)

Поддерживает геттер и сеттер:

const fullName = computed({
get() { return firstName.value + ' ' + lastName.value },
set(newValue) { /* разбор newValue */ }
})

watch

Наблюдает за изменениями реактивных данных.

import { watch } from 'vue'
watch(count, (newVal, oldVal) => {
console.log(`count изменился с ${oldVal} на ${newVal}`)
})

Типы наблюдаемых значений:

  • ref
  • reactive
  • геттер-функция
  • массив источников

Опции watch:

  • immediate: true — запуск немедленно
  • deep: true — глубокое наблюдение за объектами
  • flush: 'pre' | 'post' | 'sync' — момент выполнения колбэка

watchEffect

Автоматически отслеживает зависимости и выполняет функцию при их изменении.

import { watchEffect } from 'vue'
watchEffect(() => {
console.log(count.value)
})

Не требует явного указания источника.


3. Компоненты

Определение компонента

Через объект:

const MyComponent = {
props: ['title'],
template: '<h1>{{ title }}</h1>'
}

Через defineComponent (рекомендуется для TypeScript):

import { defineComponent } from 'vue'
const MyComponent = defineComponent({ ... })

Регистрация компонентов

Глобальная:

app.component('MyComponent', MyComponent)

Локальная (внутри компонента):

export default {
components: { MyComponent }
}

Props

Передача данных от родителя к дочернему компоненту.

props: {
title: String,
age: { type: Number, required: true },
isActive: { type: Boolean, default: false }
}

Типы type: String, Number, Boolean, Array, Object, Date, Function, Symbol, null (для любого типа).

Опции:

  • required: true
  • default: value или default() { return ... }
  • validator(value) { return condition }

Emits

Объявление событий, которые может выбросить компонент.

emits: ['update:title', 'submit']

С проверкой типов:

emits: {
submit: (payload) => typeof payload === 'object'
}

Выброс события:

emit('submit', data)

Slots

Передача контента в компонент.

По умолчанию:

<my-component>Контент слота</my-component>

Именованные слоты:

<my-component>
<template #header>Заголовок</template>
<template #footer>Подвал</template>
</my-component>

Scoped slots (слоты с данными):

<my-component v-slot="{ user }">
{{ user.name }}
</my-component>

Внутри компонента:

<slot :user="currentUser"></slot>

provide / inject

Передача данных через дерево компонентов без пропсов.

Провайдер:

import { provide } from 'vue'
provide('theme', 'dark')

Инжектор:

import { inject } from 'vue'
const theme = inject('theme', 'light') // 'light' — значение по умолчанию

Работает с ref и reactive — реактивность сохраняется.


4. Директивы

Встроенные директивы

v-bind

Привязка атрибутов или свойств.

<img v-bind:src="imageSrc" />
<!-- сокращённо -->
<img :src="imageSrc" />

Модификаторы:

  • .prop — привязка как DOM-свойство
  • .attr — привязка как атрибут
  • .camel — преобразование kebab-case в camelCase

v-on

Обработка событий.

<button v-on:click="handleClick">Клик</button>
<!-- сокращённо -->
<button @click="handleClick">Клик</button>

Модификаторы:

  • .stop — остановка всплытия
  • .prevent — предотвращение действия по умолчанию
  • .capture — обработка на фазе перехвата
  • .self — только если событие от самого элемента
  • .once — однократное срабатывание
  • .passive — пассивный обработчик
  • Клавиатурные: .enter, .esc, .space, .up, .down и т.д.
  • Мышь: .left, .right, .middle

v-if / v-else-if / v-else

Условный рендеринг.

<div v-if="isVisible">Видим</div>
<div v-else>Скрыт</div>

v-show

Переключение видимости через CSS display.

<div v-show="isVisible">Всегда в DOM</div>

v-for

Рендеринг списков.

<li v-for="item in items" :key="item.id">{{ item.name }}</li>

С индексом:

<li v-for="(item, index) in items" :key="index">{{ index }}: {{ item }}</li>

Можно использовать с объектами:

<span v-for="(value, key, index) in object" :key="key">
{{ index }}. {{ key }}: {{ value }}
</span>

v-model

Двусторонняя привязка данных.

На <input>:

<input v-model="message" />

Эквивалентно:

<input :value="message" @input="message = $event.target.value" />

Модификаторы:

  • .lazy — синхронизация по change, а не input
  • .number — автоматическое преобразование в число
  • .trim — удаление пробелов по краям

На компонентах:

<custom-input v-model="searchText" />

Внутри компонента:

props: ['modelValue'],
emits: ['update:modelValue'],
template: `<input :value="modelValue" @input="$emit('update:modelValue', $event.target.value)" />`

v-text / v-html

Установка текстового или HTML-содержимого.

<span v-text="msg"></span>
<div v-html="rawHtml"></div>

⚠️ v-html не очищает содержимое — уязвимость XSS при использовании ненадёжных данных.

v-cloak

Скрывает неразобранные шаблоны до инициализации Vue.

<div v-cloak>{{ message }}</div>

Требует CSS:

[v-cloak] { display: none; }

5. Жизненный цикл компонента

Options API хуки

  • beforeCreate
  • created
  • beforeMount
  • mounted
  • beforeUpdate
  • updated
  • beforeUnmount
  • unmounted

Composition API аналоги

  • onBeforeMount
  • onMounted
  • onBeforeUpdate
  • onUpdated
  • onBeforeUnmount
  • onUnmounted
  • onErrorCaptured
  • onRenderTracked
  • onRenderTriggered

Пример:

import { onMounted } from 'vue'
onMounted(() => {
console.log('Компонент смонтирован')
})

6. Composition API

setup()

Основная функция компонента в Composition API.

Параметры:

  • props — реактивные пропсы
  • context — объект с attrs, slots, emit, expose

Возврат:

  • объект с переменными и методами, доступными в шаблоне
  • функция рендеринга
setup(props, { emit }) {
const count = ref(0)
const increment = () => {
count.value++
emit('change', count.value)
}
return { count, increment }
}

expose()

Ограничивает публичный API компонента при обращении через $refs.

setup(props, { expose }) {
const publicMethod = () => { ... }
expose({ publicMethod })
}

7. Teleport

Рендеринг содержимого вне иерархии DOM компонента.

<teleport to="body">
<div>Модальное окно</div>
</teleport>

Полезно для модалок, тултипов, всплывающих окон.


8. Suspense

Обработка асинхронных зависимостей (например, async setup).

<Suspense>
<template #default>
<AsyncComponent />
</template>
<template #fallback>
<div>Загрузка...</div>
</template>
</Suspense>

Компонент с async setup:

async setup() {
const data = await fetchData()
return { data }
}

9. Конфигурация приложения

app.config

errorHandler

Глобальный обработчик ошибок.

app.config.errorHandler = (err, instance, info) => {
console.error('Ошибка:', err, info)
}

warnHandler

Обработчик предупреждений.

globalProperties

Добавление глобальных свойств (аналог $ в Vue 2).

app.config.globalProperties.$http = axios

optionMergeStrategies

Настройка стратегий слияния опций.

performance

Включение метрик производительности (только в dev-режиме).


10. Плагины

Подключение через app.use(plugin, options).

Плагин — функция или объект с методом install.

const MyPlugin = {
install(app, options) {
app.directive('focus', ...)
app.provide('config', options)
}
}
app.use(MyPlugin, { apiKey: '123' })

11. Типы данных и ограничения

Поддерживаемые типы реактивности

  • Примитивы: string, number, boolean, bigint, symbol
  • Объекты: Object, Array, Map, Set, WeakMap, WeakSet
  • Встроенные: Date, RegExp, Promise

Ограничения

  • Свойства, добавленные после создания реактивного объекта, не являются реактивными (используй Vue.set в Vue 2, в Vue 3 этого нет — всё реактивно благодаря Proxy)
  • Индексы массива нельзя отслеживать напрямую — используй splice, push, pop и другие мутации
  • Прямое присваивание по индексу работает в Vue 3

12. Маршрутизация (Vue Router)

Установка

npm install vue-router@4

Базовая настройка

import { createRouter, createWebHistory } from 'vue-router'
import Home from './views/Home.vue'
import About from './views/About.vue'

const routes = [
{ path: '/', component: Home },
{ path: '/about', component: About }
]

const router = createRouter({
history: createWebHistory(),
routes
})

app.use(router)

Динамические сегменты

{ path: '/user/:id', component: User }

Доступ через route.params.id.

Вложенные маршруты

{
path: '/user/:id',
component: User,
children: [
{ path: 'profile', component: UserProfile },
{ path: 'posts', component: UserPosts }
]
}

Требует <router-view /> внутри шаблона User.

Именованные маршруты

{ path: '/user/:id', name: 'user', component: User }

Использование:

<router-link :to="{ name: 'user', params: { id: 123 }}">Профиль</router-link>

Программная навигация

router.push('/about')
router.push({ name: 'user', params: { id: 1 } })
router.replace({ path: '/login' })
router.go(-1) // назад

Глобальные хуки

  • router.beforeEach(to, from, next) — защита маршрутов
  • router.afterEach(to, from) — аналитика, скролл

Meta-поля

{ path: '/admin', component: Admin, meta: { requiresAuth: true } }

Проверка в beforeEach:

if (to.meta.requiresAuth && !isAuthenticated) next('/login')

Lazy-loading компонентов

{ path: '/about', component: () => import('./views/About.vue') }

13. Управление состоянием

Pinia (официальная библиотека для Vue 3)

Установка

npm install pinia

Создание хранилища

import { createPinia } from 'pinia'
app.use(createPinia())

Определение store

import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0
}),
getters: {
doubleCount: (state) => state.count * 2
},
actions: {
increment() {
this.count++
}
}
})

Использование в компоненте

import { useCounterStore } from '@/stores/counter'
const store = useCounterStore()
store.increment()

Особенности Pinia:

  • Поддержка TypeScript без boilerplate
  • Отсутствие мутаций (только действия)
  • Модульность без вложенности
  • Поддержка SSR

Vuex (устаревший, но поддерживаемый)

Структура

  • state — данные
  • getters — вычисляемые свойства
  • mutations — синхронные изменения
  • actions — асинхронные операции
  • modules — модульность

14. Инструменты сборки

Vite (рекомендуется для Vue 3)

Создание проекта

npm create vue@latest

Преимущества

  • Мгновенный запуск dev-сервера
  • Нативная поддержка ES-модулей
  • Hot Module Replacement (HMR)
  • Встроенная поддержка TypeScript, JSX, CSS препроцессоров

Vue CLI (устаревший)

Поддерживается, но не рекомендуется для новых проектов.


15. Однофайловые компоненты (.vue)

Структура:

<template>
<div>{{ message }}</div>
</template>

<script setup>
import { ref } from 'vue'
const message = ref('Привет')
</script>

<style scoped>
div { color: red; }
</style>

Блоки

  • <template> — один корневой элемент
  • <script> или <script setup> — логика
  • <style> — стили, с атрибутами scoped, module

Атрибуты script

  • setup — Composition API без return
  • lang="ts" — TypeScript
  • name — имя компонента для DevTools

Атрибуты style

  • scoped — изоляция стилей
  • module — CSS Modules
  • lang="scss" — препроцессоры

16. Server-Side Rendering (SSR)

Vue + Vite SSR

Официальный подход через create-vue с флагом SSR.

Nuxt.js

Фреймворк поверх Vue для SSR, генерации статики, мета-тегов.


17. DevTools

Vue DevTools

Браузерное расширение для:

  • Инспекции компонентов
  • Просмотра состояния (Pinia/Vuex)
  • Отслеживания событий
  • Профилирования производительности

Поддерживает Vue 3, Pinia, маршруты.


18. Оптимизации

Lazy-loading компонентов

const AsyncComponent = defineAsyncComponent(() =>
import('./components/HeavyComponent.vue')
)

keep-alive

Кэширование компонентов при переключении.

<keep-alive>
<component :is="currentView" />
</keep-alive>

Атрибуты:

  • include / exclude — список имён
  • max — максимальное число кэшируемых экземпляров

v-memo (Vue 3.2+)

Мемоизация поддерева при рендере.

<div v-for="item in list" :key="item.id" v-memo="[item.id === selected]">
{{ item.name }}
</div>

Обновляет DOM только если изменяется условие в массиве.

Компиляция шаблонов

Vue компилирует шаблоны в функции рендеринга. В production-сборке отключается проверка типов и предупреждения.


19. Типизация (TypeScript)

defineComponent

Обеспечивает правильную типизацию опций.

import { defineComponent } from 'vue'
export default defineComponent({
props: { msg: String },
setup(props) {
// props.msg — string | undefined
}
})

defineProps / defineEmits (в <script setup>)

const props = defineProps<{
msg: string
}>()

const emit = defineEmits<{
(e: 'change', id: number): void
}>()

withDefaults

Значения по умолчанию для props в TS:

const props = withDefaults(defineProps<{
size?: 'small' | 'medium' | 'large'
}>(), {
size: 'medium'
})

20. Тестирование

Vitest + Vue Test Utils

Официальный стек для unit-тестов.

Пример:

import { mount } from '@vue/test-utils'
import MyComponent from './MyComponent.vue'

test('renders message', () => {
const wrapper = mount(MyComponent, {
props: { message: 'Hello' }
})
expect(wrapper.text()).toContain('Hello')
})

Cypress / Playwright

Для end-to-end тестирования.


21. Best Practices

  • Используйте Composition API для сложной логики
  • Разделяйте логику на composable-функции (useXxx)
  • Избегайте глубокой вложенности компонентов
  • Используйте key в v-for для уникальной идентификации
  • Не мутируйте props напрямую
  • Используйте v-model с модификаторами для контроля ввода
  • Минимизируйте использование глобальных переменных
  • Разделяйте представление и бизнес-логику

22. Сравнение с другими фреймворками

ХарактеристикаVueReactAngular
ПарадигмаДекларативнаяДекларативнаяДекларативная
РеактивностьАвтоматическаяЧерез setState / HooksZone.js + ChangeDetection
ШаблоныHTML-basedJSXHTML + специальные синтаксисы
Кривая обученияНизкаяСредняяВысокая
Размер~30 КБ (gzip)~40 КБ (с React DOM)>100 КБ
TypeScriptПолная поддержкаРодная поддержкаВстроен

23. Примеры использования

Простой счётчик

<script setup>
import { ref } from 'vue'
const count = ref(0)
const increment = () => count.value++
</script>

<template>
<button @click="increment">{{ count }}</button>
</template>

Форма с валидацией

<script setup>
import { ref } from 'vue'
const email = ref('')
const isValid = ref(true)

const validate = () => {
isValid.value = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email.value)
}
</script>

<template>
<input v-model="email" @blur="validate" :class="{ error: !isValid }" />
<p v-if="!isValid">Неверный email</p>
</template>

Список с фильтрацией

<script setup>
import { ref, computed } from 'vue'
const items = ref(['Apple', 'Banana', 'Orange'])
const query = ref('')
const filtered = computed(() =>
items.value.filter(i => i.toLowerCase().includes(query.value.toLowerCase()))
)
</script>

<template>
<input v-model="query" placeholder="Поиск..." />
<ul>
<li v-for="item in filtered" :key="item">{{ item }}</li>
</ul>
</template>